package avicit.bdp.dms.tdm.service;

import avicit.bdp.common.base.BaseService;
import avicit.bdp.common.utils.BdpLogUtil;
import avicit.bdp.core.constant.Constants;
import avicit.bdp.dms.tdm.dao.ProcessApproveDao;
import avicit.bdp.dms.tdm.dto.AssetApplyDTO;
import avicit.bdp.dms.tdm.dto.ProcessApproveDTO;
import avicit.bdp.dms.tdm.utils.CheckerStatus;
import avicit.bdp.dms.tdm.utils.FlowType;
import avicit.bdp.dms.tdm.utils.SysOrgUtils;
import avicit.platform6.api.bpm.BpmOperateClient;
import avicit.platform6.api.bpm.BpmProcessDefinitionClient;
import avicit.platform6.api.bpm.BpmProcessInstanceClient;
import avicit.platform6.api.bpm.BpmTaskClient;
import avicit.platform6.api.bpm.dto.HistoryTaskVo;
import avicit.platform6.api.bpm.dto.ProcessParameter;
import avicit.platform6.api.syslookup.dto.SysLookupSimpleVo;
import avicit.platform6.api.system.ConvertColumnClient;
import avicit.platform6.api.system.SysLookupClient;
import avicit.platform6.api.system.SysUserDeptPositionClient;
import avicit.platform6.api.system.impl.SystemConstant;
import avicit.platform6.api.sysuser.dto.SysOrg;
import avicit.platform6.bpmclient.dto.sys.ProcessDefInfoVo;
import avicit.platform6.bpmreform.bpmbusiness.dto.StartResultBean;
import avicit.platform6.commons.utils.BusinessUtil;
import avicit.platform6.commons.utils.ComUtil;
import avicit.platform6.commons.utils.JsonUtil;
import avicit.platform6.commons.utils.PojoUtil;
import avicit.platform6.core.context.ThreadContextHelper;
import avicit.platform6.core.exception.BusinessException;
import avicit.platform6.core.exception.DaoException;
import avicit.platform6.core.exception.UtilsException;
import avicit.platform6.core.properties.PlatformConstant;
import avicit.platform6.core.rest.msg.QueryRespBean;
import avicit.platform6.modules.system.syslog.service.SysLogUtil;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

/**
 * @金航数码科技有限责任公司
 * @作者：${tableInfo.classCreator}
 * @邮箱：${tableInfo.classMailbox}
 * @创建时间： 2023-11-14 16:03
 * @类说明：
 * @修改记录：
 */
@Service
public class ProcessApproveService extends BaseService<ProcessApproveDao, ProcessApproveDTO> {

    private static final Logger logger = LoggerFactory.getLogger(ProcessApproveService.class);

    @Autowired
    private ProcessApproveDao processApproveDao;
    @Autowired
    private AssetApplyService assetApplyService;
    @Autowired
    private ConvertColumnClient convertColumnClient;
    @Autowired
    private BpmProcessInstanceClient bpmProcessInstanceClient;
    @Autowired
    private SysOrgUtils sysOrgUtils;
    @Autowired
    private SysUserDeptPositionClient sysUserDeptPositionClient;
    @Autowired
    private BpmOperateClient bpmOperateClient;
    @Autowired
    private SysLookupClient sysLookupClient;
    @Autowired
    private BpmProcessDefinitionClient bpmProcessDefinitionClient;
    @Autowired
    private BpmTaskClient bpmTaskClient;

    /**
     * 我的审核-按条件分页查询
     *
     * @param pageNo
     * @param pageSize
     * @return
     * @throws Exception
     */
    @Transactional(readOnly = true)
    public QueryRespBean<ProcessApproveDTO> getMyProcessPageList(String businessTitle, Integer flowType,
                                                                 String bpmType, String bpmState,
                                                                 Integer pageNo, Integer pageSize)
            throws Exception {
        QueryRespBean<ProcessApproveDTO> queryRespBean = new QueryRespBean<>();
        String loginUserId = ThreadContextHelper.getUserId();
        String loginUserName = ThreadContextHelper.getUserName();

        PageHelper.startPage(pageNo, pageSize);
        Page<ProcessApproveDTO> pageList = processApproveDao.getMyProcessPageList(businessTitle, flowType, bpmType, bpmState, loginUserId, loginUserName);
        valueMyProcessConvert(pageList.getResult());
        queryRespBean.setResult(pageList);
        BdpLogUtil.log4Query(queryRespBean);
        return queryRespBean;
    }

    /**
     * 我的申请-按条件分页查询
     *
     * @param pageNo
     * @param pageSize
     * @return
     * @throws Exception
     */
    @Transactional(readOnly = true)
    public QueryRespBean<ProcessApproveDTO> getMyApplyPageList(String keyWord, Integer resourceType,
                                                               String applyTimeBegin, String applyTimeEnd,
                                                               String bpmType, String bpmState,
                                                               Integer pageNo, Integer pageSize)
            throws Exception {
        QueryRespBean<ProcessApproveDTO> queryRespBean = new QueryRespBean<>();
        String loginUserId = ThreadContextHelper.getUserId();
        String loginUserName = ThreadContextHelper.getUserName();
        PageHelper.startPage(pageNo, pageSize);
        Page<ProcessApproveDTO> pageList = processApproveDao.getMyApplyPageList(keyWord, resourceType, applyTimeBegin,
                applyTimeEnd, bpmType, bpmState, loginUserId, loginUserName);
        valueMyApplyConvert(pageList.getResult());
        queryRespBean.setResult(pageList);
        BdpLogUtil.log4Query(queryRespBean);
        return queryRespBean;
    }

    /**
     * 新增并启动流程
     *
     * @param processParam
     * @return
     */
    @Transactional
    public StartResultBean saveAndStartProcess(ProcessParameter<ProcessApproveDTO> processParam) {
        String userId = ThreadContextHelper.getUserId();
        String deptId = ThreadContextHelper.getDeptId();
        if (StringUtils.isEmpty(deptId)) {
            deptId = sysUserDeptPositionClient.getChiefDeptIdBySysUserId(ThreadContextHelper.getUserId());
        }
        /* 设置启动流程所需要的参数 */
        Map<String, String> parameter = new HashMap<>();
        parameter.put("processDefId", processParam.getProcessDefId());
        parameter.put("formCode", processParam.getFormCode());
        parameter.put("jsonString", processParam.getJsonString());
        parameter.put("userId", userId);
        parameter.put("deptId", deptId);
        processParam.getBean().setOrgIdentity(ThreadContextHelper.getOrgId());
        StartResultBean result = this.insertProcessApproveAndStartProcess(processParam.getBean(), parameter);
        return result;
    }

    /**
     * 自动启动流程
     *
     * @param processApprove
     * @param formCode
     * @return java.lang.String
     */
    @Transactional
    public String startProcessTask(ProcessApproveDTO processApprove, String formCode, String orgId) {
        String userId = ThreadContextHelper.getUserId();
        String deptId = ThreadContextHelper.getDeptId();
        if (StringUtils.isEmpty(deptId)) {
            deptId = sysUserDeptPositionClient.getChiefDeptIdBySysUserId(ThreadContextHelper.getUserId());
        }
        processApprove.setOrgIdentity(ThreadContextHelper.getOrgId());
        //变量集合
        Map<String, Object> variables = new HashMap<>();
        String result;
        ProcessApproveDTO old = this.mapper.getMyProcessApproveByUserId(userId, processApprove.getBusinessId(), processApprove.getFlowType());
        if (old != null) {
            HistoryTaskVo task = processApproveDao.getMyToDoTaskByUserId(old.getId(), userId);
            if (task != null) {
                // 自动提交第一个节点
                result = bpmOperateClient.completeTask(task.getProcessInstance(), task.getDbid(), variables, "同意");
                logger.info("taskId：" + task.getProcessInstance() + "-" + task.getDbid());
                return result;
            }
        }

        //业务操作 保存申请记录
        this.save(processApprove);

        //把表单对象转换成map,传递给流程变量
        Map<String, Object> pojoMap = null;
        try {
            pojoMap = (Map<String, Object>) PojoUtil.toMap(processApprove);
        } catch (Exception e) {
            throw new BusinessException("PojoUtil.toMap转换失败", e);
        }
        variables.putAll(pojoMap);
        //待办标题变量
        variables.put("taskTitle", processApprove.getBusinessTitle());
        //查询指定组织的流程列表，默认是第一个
        List<ProcessDefInfoVo> processDefInfoVoList = bpmProcessDefinitionClient.findProcessDefinitionByFormCode(formCode, null, false, orgId);
        String processInstanceIDefId = "";
        if (CollectionUtils.isNotEmpty(processDefInfoVoList)) {
            processInstanceIDefId = processDefInfoVoList.get(0).getDbid();
        }
        // 启动流程实例
        String processInstanceId = bpmOperateClient.startProcessInstanceById(processInstanceIDefId, formCode, userId, deptId, variables);
        // 返回第一个启动的流程实例节点
        StartResultBean resultBean = bpmProcessInstanceClient.getStartResultBean(processInstanceId, processApprove.getId(), userId);
        bpmOperateClient.changeTaskTitleByFormId(resultBean.getFormId(), processApprove.getBusinessTitle());
        // 自动提交第一个节点
        result = bpmOperateClient.completeTask(processInstanceId, resultBean.getTaskId(), variables, "同意");

        return result;
    }

    /**
     * 保存表单并启动流程
     *
     * @param processApprove 表单对象
     * @param parameter      启动流程所需要的参数
     * @return StartResultBean
     */
    @Transactional
    public StartResultBean insertProcessApproveAndStartProcess(ProcessApproveDTO processApprove, Map<String, String> parameter) {
        Assert.notNull(parameter, "启动流程失败，请传递流程启动参数！");
        String processDefId = parameter.get("processDefId");
        String formCode = parameter.get("formCode");
        String jsonString = parameter.get("jsonString");
        String userId = parameter.get("userId");
        String deptId = parameter.get("deptId");
        Assert.hasText(processDefId, "启动流程失败，请传递流程启动参数！");
        //业务操作
        this.save(processApprove);
        //变量集合
        Map<String, Object> variables = new HashMap<>();
        //web表单传递过来(除表单对象外)的变量，可以为空
        if (StringUtils.isNotEmpty(jsonString)) {
            Map<String, Object> extVariables = JsonUtil.parseJSON2Map(jsonString);
            variables.putAll(extVariables);
        }
        //把表单对象转换成map,传递给流程变量
        Map<String, Object> pojoMap = null;
        try {
            pojoMap = (Map<String, Object>) PojoUtil.toMap(processApprove);
        } catch (Exception e) {
            throw new UtilsException("PojoUtil.toMap转换失败", e);
        }
        variables.putAll(pojoMap);
        String processInstanceId = bpmOperateClient.startProcessInstanceById(processDefId, formCode, userId, deptId, variables);
        // 返回对象
        return bpmProcessInstanceClient.getStartResultBean(processInstanceId, processApprove.getId(), userId);
    }

    /**
     * 批量删除数据
     *
     * @param ids 逗号分隔的id串
     */
    @Transactional
    public void deleteByIds(String ids) {
        if (StringUtils.isEmpty(ids)) {
            throw new BusinessException("ids参数没传入");
        }
        for (String id : ids.split(",")) {
            //删除业务数据
            deleteProcessById(id);
        }
        String logTitle = "删除id为：【" + ids + "】我申请的资产";
        BdpLogUtil.log("我的资产模块", logTitle, PlatformConstant.OpType.delete);
    }

    /**
     * 按主键单条删除
     *
     * @param id 主键id
     * @return int
     */
    @Transactional
    public void deleteProcessById(String id) {
        if (StringUtils.isEmpty(id)) {
            throw new BusinessException("删除失败！传入的参数主键为null");
        }
        ProcessApproveDTO processApprove = this.selectByPrimaryKey(id);
        if (processApprove == null) {
            throw new BusinessException("删除失败！对象不存在");
        }
        //记录日志
        SysLogUtil.log4Delete(processApprove);
        //删除业务数据
        this.deleteByPrimaryKey(id);
        //删除业务子表数据
        this.deleteProcessChildData(processApprove);
        //删除关联流程实例
        String processInstanceId = bpmProcessInstanceClient.getProcessInstanceIdByFormid(id);
        if (StringUtils.isNotEmpty(processInstanceId)) {
            bpmOperateClient.deleteProcessInstanceCascade(processInstanceId);
        }
    }

    /**
     * 删除业务子表数据
     *
     * @param processApprove 流程对象
     */
    private void deleteProcessChildData(ProcessApproveDTO processApprove) {
        int flowType = processApprove.getFlowType();
        if (flowType == FlowType.APPLY.getCode()) {
            AssetApplyDTO apply = assetApplyService.queryById(processApprove.getBusinessId());
            if (apply == null) {
                return;
            }
            //删除申请表
            assetApplyService.deleteByPrimaryKey(apply.getId());
        }
    }

    /**
     * 新增对象
     *
     * @param dto 保存对象
     * @return String
     */
    @Transactional
    public String save(ProcessApproveDTO dto) {
        try {
            dto.setId(ComUtil.getId());
            PojoUtil.setSysProperties(dto, PlatformConstant.OpType.insert);
            this.insert(dto);
            // 记录日志
            SysLogUtil.log4Insert(dto);
            return dto.getId();
        } catch (Exception e) {
            throw new DaoException(e.getMessage(), e);
        }
    }

    /**
     * 修改对象部分字段
     *
     * @param dto 修改对象
     * @return int
     */
    @Transactional
    public int update(ProcessApproveDTO dto) {
        try {
            int count = this.updateByPrimaryKey(getUpdateDto(dto));
            if (count == 0) {
                throw new DaoException("数据失效，请重新更新");
            }
            return count;
        } catch (Exception e) {
            throw new DaoException(e.getMessage(), e);
        }
    }

    /**
     * 通过主键查询单条记录
     *
     * @param id 主键id
     */
    @Transactional(readOnly = true)
    public ProcessApproveDTO queryById(String id) {
        try {
            ProcessApproveDTO dto = this.selectByPrimaryKey(id);
            // 记录日志
            if (dto != null) {
                SysLogUtil.log4Query(dto);
            }
            return dto;
        } catch (Exception e) {
            throw new DaoException(e.getMessage(), e);
        }
    }

    /**
     * 流程服务回调方法（按主表主键单条删除业务数据）
     *
     * @param id 主键id
     * @return int
     */
    @Transactional
    public int deleteById(String id) {
        if (StringUtils.isEmpty(id)) {
            throw new BusinessException("删除失败！传入的参数主键为null");
        }
        try {
            // 记录日志
            ProcessApproveDTO approveDTO = queryById(id);
            if (approveDTO == null) {
                throw new BusinessException("删除失败！对象不存在");
            }
            SysLogUtil.log4Delete(approveDTO);
            // 删除业务数据
            return processApproveDao.deleteByPrimaryKey(id);
        } catch (Exception e) {
            throw new BusinessException(e.getMessage(), e);
        }
    }

    /**
     * 内部方法，获取修改的dto对象
     *
     * @param dto
     * @return
     */
    private ProcessApproveDTO getUpdateDto(ProcessApproveDTO dto) {
        ProcessApproveDTO oldDTO = this.selectByPrimaryKey(dto.getId());
        if (oldDTO == null) {
            throw new DaoException("数据不存在");
        }
        //记录日志
        SysLogUtil.log4Update(dto, oldDTO);
        PojoUtil.setSysProperties(dto, PlatformConstant.OpType.update);
        PojoUtil.copyProperties(oldDTO, dto, true);
        return oldDTO;
    }

    /**
     * 通过平台API将字段值转换为名称，包括通用选择组件、通用代码
     *
     * @param processApproveList
     */
    private void valueMyProcessConvert(List<ProcessApproveDTO> processApproveList) {
        //循环组装请求数据
        Map<String, Set<String>> convertFormData = new HashMap<>();
        for (ProcessApproveDTO processApprove : processApproveList) {
            BusinessUtil.createConvertSet(convertFormData, Constants.BDP_DATA_SECRET_LEVEL_KEY, processApprove.getSecretLevel());
            BusinessUtil.createConvertSet(convertFormData, "BDP_DAM_FLOW_TYPE", String.valueOf(processApprove.getFlowType()));
            BusinessUtil.createConvertSet(convertFormData, SystemConstant.USER, processApprove.getCreatedBy());
        }
        if (convertFormData.size() > 0) {
            //获取请求结果
            Map<String, Map<String, String>> convertResultData = convertColumnClient.replace(convertFormData);
            //循环设置Alias或Name的值
            for (ProcessApproveDTO processApprove : processApproveList) {
                processApprove.setSecretLevelName(BusinessUtil.convertFormat(convertResultData, Constants.BDP_DATA_SECRET_LEVEL_KEY, processApprove.getSecretLevel()));
                processApprove.setFlowTypeName(BusinessUtil.convertFormat(convertResultData, "BDP_DAM_FLOW_TYPE", String.valueOf(processApprove.getFlowType())));
                //流程的编码转换成名称
                processApprove.setBpmState(processApprove.getBusinessstate_());
                processApprove.setBusinessstate_(BusinessUtil.processStateCode2StateName(processApprove.getBusinessstate_()));
                //冗余字段赋值
                processApprove.setSubmitTime(processApprove.getCreationDate());
                processApprove.setSubmitPerson(processApprove.getCreatedBy());
                processApprove.setSubmitPersonName(BusinessUtil.convertFormat(convertResultData, SystemConstant.USER, processApprove.getCreatedBy()));
                SysOrg org = sysOrgUtils.getOrgByUserId(processApprove.getCreatedBy());
                if (org != null) {
                    processApprove.setSubmitOrg(org.getId());
                    processApprove.setSubmitOrgName(org.getOrgName());
                }
            }
        }
    }

    /**
     * 通过平台API将字段值转换为名称，包括通用选择组件、通用代码
     */
    private void valueMyApplyConvert(List<ProcessApproveDTO> processApproveList) {
        //循环组装请求数据
        Map<String, Set<String>> convertFormData = new HashMap<>();
        for (ProcessApproveDTO processApprove : processApproveList) {
            BusinessUtil.createConvertSet(convertFormData, Constants.BDP_DATA_SECRET_LEVEL_KEY, processApprove.getSecretLevel());
            BusinessUtil.createConvertSet(convertFormData, "BDP_DAM_FLOW_TYPE", String.valueOf(processApprove.getFlowType()));
            BusinessUtil.createConvertSet(convertFormData, "BDP_DAM_RESOURCE_TYPE", String.valueOf(processApprove.getResourceType()));
        }
        Map<String, String> serviceTypeMap = new HashMap<>();
        Collection<SysLookupSimpleVo> lookupList = sysLookupClient.getLookUpListByTypeByAppIdNoFilter("BDP_DAM_APPLY_SERVICE_TYPE", ThreadContextHelper.getAppId());
        for (SysLookupSimpleVo vo : lookupList) {
            serviceTypeMap.put(vo.getLookupCode(), vo.getLookupName());
        }
        if (convertFormData.size() > 0) {
            //获取请求结果
            Map<String, Map<String, String>> convertResultData = convertColumnClient.replace(convertFormData);
            //循环设置Alias或Name的值
            for (ProcessApproveDTO processApprove : processApproveList) {
                processApprove.setSecretLevelName(BusinessUtil.convertFormat(convertResultData, Constants.BDP_DATA_SECRET_LEVEL_KEY, processApprove.getSecretLevel()));
                processApprove.setFlowTypeName(BusinessUtil.convertFormat(convertResultData, "BDP_DAM_FLOW_TYPE", String.valueOf(processApprove.getFlowType())));
                processApprove.setResourceTypeName(BusinessUtil.convertFormat(convertResultData, "BDP_DAM_RESOURCE_TYPE", String.valueOf(processApprove.getResourceType())));
                //审核状态转化
                processApprove.setCheckStatusName(CheckerStatus.getDescByCode(processApprove.getCheckerStatus()));
                //流程的编码转换成名称
                processApprove.setBpmState(processApprove.getBusinessstate_());
                processApprove.setBusinessstate_(BusinessUtil.processStateCode2StateName(processApprove.getBusinessstate_()));
                processApprove.setApplyTime(processApprove.getCreationDate());
                processApprove.setApplyServiceType(convertType(processApprove.getApplyServiceType(), serviceTypeMap));
                //审核状态
                //writeCheckStatus(processApprove);
            }
        }
    }

    /**
     * 转换申请服务代码名称
     */
    private String convertType(String code, Map<String, String> serviceTypeMap) {
        if (StringUtils.isBlank(code)) {
            return "";
        }
        String[] codes = code.split(",");
        List<String> list = new ArrayList<>();
        for (String c : codes) {
            list.add(serviceTypeMap.getOrDefault(c, ""));
        }
        return String.join(",", list);
    }

    /**
     * 审核状态赋值
     *
     * @param processApprove 流程对象
     */
    private void writeCheckStatus(ProcessApproveDTO processApprove) {
        Map<String, Object> map = bpmProcessInstanceClient.doGettracks(processApprove.getDbid_());
        if (map == null) {
            return;
        }
        if (map.get("tracklist") == null) {
            return;
        }
        ArrayList<ArrayList<LinkedHashMap<String, String>>> trackVoList = (ArrayList<ArrayList<LinkedHashMap<String, String>>>) map.get("tracklist");
        if (CollectionUtils.isNotEmpty(trackVoList) && trackVoList.size() > 2) {
            ArrayList<LinkedHashMap<String, String>> linkedHashMapArrayList = trackVoList.get(trackVoList.size() - 2);
            for (LinkedHashMap<String, String> maps : linkedHashMapArrayList) {
                if ("doretreattodraft".equals(maps.get("operateType")) || "doretreattoprev".equals(maps.get("operateType"))) {
                    processApprove.setCheckerStatus(CheckerStatus.NOT_APPROVED.getCode());
                    processApprove.setCheckStatusName("退回");
                }
            }
        }
    }

    public List<ProcessApproveDTO> queryProcessApproveByBusinessIdList(List<String> idLists) {
        return this.mapper.queryProcessApproveByBusinessIdList(idLists);
    }
}